#include "stdafx.h"
#include "shaders.h"

using namespace std ; 

Shaders::Shaders(void) { }

Shaders::~Shaders(void) { }

void Shaders::init(const char * vertshader,const char * fragshader)
{
	vertexshader = initshaders(GL_VERTEX_SHADER, vertshader);
    fragmentshader = initshaders(GL_FRAGMENT_SHADER, fragshader);
    shaderprogram = initprogram(vertexshader, fragmentshader);
}

GLint Shaders::getUniformLocation(const char * name)
{
	return glGetUniformLocation(shaderprogram, name);
}

string Shaders::textFileRead (const char * filename) 
{
	string str, ret = "" ; 
	ifstream in ; 
	in.open(filename) ; 
	
	if (in.is_open()) 
	{
		getline (in, str) ; 
		while (in) 
		{
			ret += str + "\n" ; 
			getline (in, str) ; 
		}
		//    cout << "Shader below\n" << ret << "\n" ; 
		return ret ; 
	}
	else 
	{
		cerr << "Unable to Open File " << filename << "\n" ; 
		throw 2 ; 
	}
}

void Shaders::programerrors (const GLint program) 
{
	GLint length ; 
	GLchar * log ; 

	glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length) ; 
	log = new GLchar[length+1] ;
	glGetProgramInfoLog(program, length, &length, log) ; 
	cout << "Compile Error, Log Below\n" << log << "\n" ; 
	delete [] log ; 
}

void Shaders::shadererrors (const GLint shader) 
{
	GLint length ; 
	GLchar * log ; 
	
	glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length) ; 
	log = new GLchar[length+1] ;
	glGetShaderInfoLog(shader, length, &length, log) ; 
	cout << "Compile Error, Log Below\n" << log << "\n" ; 
	delete [] log ; 
}

GLuint Shaders::initshaders (GLenum type, const char *filename) 
{
	GLuint shader = glCreateShader(type) ; 
	GLint compiled ; 
	string str = textFileRead (filename) ; 
	GLchar * cstr = new GLchar[str.size()+1] ; 
	const GLchar * cstr2 = cstr ; // Weirdness to get a const char
  
	strcpy(cstr,str.c_str()) ; 
	glShaderSource (shader, 1, &cstr2, NULL) ; 
	glCompileShader (shader) ; 
	glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled) ; 
  
	if (!compiled) 
	{ 
		shadererrors (shader) ; 
		throw 3 ; 
	}
	return shader ; 
}

GLuint Shaders::initprogram (GLuint vertexshader, GLuint fragmentshader) 
{
	GLuint program = glCreateProgram() ; 
	GLint linked ; 
  
	glAttachShader(program, vertexshader) ; 
	glAttachShader(program, fragmentshader) ; 
	glLinkProgram(program) ; 
	glGetProgramiv(program, GL_LINK_STATUS, &linked) ; 
  
	if (linked) 
		glUseProgram(program) ;
	else 
	{ 
		programerrors(program) ; 
		throw 4 ; 
	}
  return program ; 
}
